#include "../include/variant.h"
#include <cassert>
#include "table/TableCodec.h"

namespace qb {
namespace proto {

VariantTable::VariantTable()
	: buf_encoded_(NULL)
	, buf_encoded_len_(0)
	, table_codec_(new(std::nothrow) TableCodec)
	, records_(new Records){
}

VariantTable::~VariantTable() {
	clear();
}
void VariantTable::clear()
{
	if (buf_encoded_ != NULL) {
		delete[]buf_encoded_;
		buf_encoded_ = NULL;
	}

	if (records_ != NULL) {
		for (size_t i = 0; i < records_->size(); i++) {
			delete (*records_)[i];
		}
		delete records_;
		records_ = NULL;
	}

	if (table_codec_ != NULL) {
		delete table_codec_;
		table_codec_ = NULL;
	}
}
VariantTable& VariantTable::operator= (const VariantTable& table)
{
	clear();
	table_codec_ = table.table_codec_->Copy();
	buf_encoded_len_ = table.buf_encoded_len_;
	if (table.buf_encoded_)
	{
		buf_encoded_ = new unsigned char[buf_encoded_len_ + 1];
		memcpy(buf_encoded_, table.buf_encoded_, buf_encoded_len_);
		buf_encoded_[buf_encoded_len_] = 0;
	}
	records_ = new Records();
	for (int i = 0; i < (int)table.records_->size();i++)
	{
		records_->push_back(new VariantRecord(table_codec_,i));
	}
	return *this;
}

VariantRecord* VariantTable::addRecord() {
	int rows = records_->size();
	VariantRecord* record = new(std::nothrow) 
		VariantRecord(table_codec_, rows);
	records_->push_back(record);
	table_codec_->AddRow();
	return record;
}

int VariantTable::encode()const {
	const int capcity = 1024 * 1024;
	if (buf_encoded_ == NULL) {
		buf_encoded_ = new unsigned char[capcity];
	}
	
	buf_encoded_len_ = 0;
	memset(buf_encoded_, 0, sizeof(unsigned char) * capcity);

	int rows = records_->size();
	table_codec_->AddDefaults(rows == 0 ? 0 : (rows - 1));

	bool zipped = false;
	buf_encoded_len_ = table_codec_->Encode(buf_encoded_, capcity, zipped);
	return buf_encoded_len_;
}

int VariantTable::size()const {
	return buf_encoded_len_;
}

const char* VariantTable::c_str()const {
	return (char*)buf_encoded_;
}

//////////////////////////////////////////////////////////////////
VariantTableDecoder::VariantTableDecoder()
	: table_codec_(new(std::nothrow)TableCodec)
	, records_(new(std::nothrow)Records){
}

VariantTableDecoder::~VariantTableDecoder() {
	if (records_ != NULL) {
		for (size_t i=0; i<records_->size(); i++) {
			delete (*records_)[i];
		}
		delete records_;
		records_ = NULL;
	}
	if (table_codec_ != NULL) {
		delete table_codec_;
		table_codec_ = NULL;
	}
}

bool VariantTableDecoder::decode(const char* data, size_t size) {
	if (data!= NULL && size>0) {
		table_codec_->Decode((unsigned char*)const_cast<char*>(data), size);

		for (int row = 0; row < getRow(); row++) {
			VariantRecord* record = new VariantRecord(table_codec_, row);
			records_->push_back(record);
		}
		return true;
	}
	return false;
}

int VariantTableDecoder::getRow() {
	return table_codec_->GetRow();
}

int VariantTableDecoder::getCol() {
	return table_codec_->GetCol();
}

VariantTableDecoder::iterator VariantTableDecoder::begin() {
	return iterator(this, 0);
}

VariantTableDecoder::iterator VariantTableDecoder::end() {
	return iterator(this, records_->size());
}

/////////////////////////////////////////////////////////////////////
typedef VariantTableDecoder::iterator iterator;
iterator::iterator(VariantTableDecoder* dec, int index)
	:dec_(dec), index_(index) {
}
iterator& iterator::operator++() {
	index_++;
	return *this;
}
bool iterator::operator==(const iterator& iter) const {
	return index_ == iter.index_;
}
bool iterator::operator!=(const iterator& iter)const {
	return index_ != iter.index_;
}
VariantRecord* iterator::operator->() {
	return dec_->at(index_);
}
VariantRecord* iterator::operator*() {
	return dec_->at(index_);
}

}
}
